"""
工作流实例扩展服务层
处理实例创建的新逻辑：从模板创建、复制实例、实例另存为模板
"""
import json
from typing import Dict, Any, Optional, Tuple
from datetime import datetime
from sqlalchemy.orm import Session

from models.workflow_template import WorkflowTemplate
from models.workflow_instance import WorkflowInstance
from services.workflow_template_service import WorkflowTemplateService
from services.workflow_engine import WorkflowEngine


class WorkflowInstanceService:
    """工作流实例扩展服务"""

    @staticmethod
    def create_instance_from_template(
        db: Session,
        template_id: int,
        instance_name: str,
        input_params: Optional[Dict[str, Any]] = None,
        trigger_type: str = "manual",
        trigger_user: Optional[str] = None,
        cron_expression: Optional[str] = None,
        cron_enabled: bool = False,
        workflow_definition_snapshot: Optional[Dict[str, Any]] = None,
        auto_start: bool = False,
        schedule_type: str = "manual",
        schedule_config: Optional[Dict[str, Any]] = None,
        created_by: Optional[str] = None
    ) -> Tuple[bool, str, Optional[WorkflowInstance]]:
        """
        从模板创建工作流实例

        Args:
            db: 数据库会话
            template_id: 模板ID
            instance_name: 实例名称
            input_params: 输入参数（可覆盖模板参数）
            trigger_type: 触发类型（manual/cron）
            cron_expression: Cron 表达式（可选）
            cron_enabled: 是否启用定时调度
            workflow_definition_snapshot: 工作流定义快照（可选，用于覆盖模板定义）
            auto_start: 是否自动启动（默认False，创建后状态为"未运行"）
            schedule_type: 调度类型（manual/scheduled/dependent/cron）
            schedule_config: 调度配置（JSON格式）
            created_by: 创建人

        Returns:
            (是否成功, 错误信息, 工作流实例)
        """
        try:
            # 1. 获取模板（最新版本）
            template = WorkflowTemplateService.get_template(db, template_id)
            if not template:
                return False, "模板不存在", None

            # 2. 确定工作流定义快照
            # 如果提供了自定义的工作流定义，使用它；否则使用模板的定义
            if workflow_definition_snapshot:
                workflow_snapshot = json.dumps(workflow_definition_snapshot, ensure_ascii=False)
            else:
                workflow_snapshot = template.workflow_definition

            # 3. 处理调度类型和配置
            # 合并 cron 配置到 schedule_type 和 schedule_config
            if cron_enabled and cron_expression:
                schedule_type = 'cron'
                if not schedule_config:
                    schedule_config = {}
                schedule_config['cron_expression'] = cron_expression

            # 4. 确定初始状态
            # 规则：
            # - 如果启用定时任务（cron），直接为"初始化"状态（避免混淆）
            # - 如果 auto_start=True，为"初始化"状态
            # - 如果调度类型为 scheduled 或 dependent，为"初始化"状态（等待调度）
            # - 否则为"未运行"状态
            if cron_enabled or auto_start or schedule_type in ['scheduled', 'dependent', 'cron']:
                initial_status = WorkflowEngine.STATUS_INIT
            else:
                initial_status = WorkflowEngine.STATUS_NOT_STARTED

            # 5. 序列化调度配置
            schedule_config_json = None
            if schedule_config:
                schedule_config_json = json.dumps(schedule_config, ensure_ascii=False)

            # 6. 创建实例
            instance = WorkflowInstance(
                template_id=template.id,
                template_version=template.version,
                template_name=template.name,
                workflow_definition_snapshot=workflow_snapshot,  # 快照工作流定义
                instance_name=instance_name,
                status=initial_status,
                trigger_type=trigger_type,
                trigger_user=trigger_user or created_by,
                input_params=json.dumps(input_params or {}, ensure_ascii=False),
                cron_expression=cron_expression,
                cron_enabled=cron_enabled,
                schedule_type=schedule_type,
                schedule_config=schedule_config_json,
                created_by=created_by or trigger_user
            )

            db.add(instance)
            db.commit()
            db.refresh(instance)

            return True, "", instance

        except Exception as e:
            db.rollback()
            return False, f"从模板创建实例失败: {str(e)}", None

    @staticmethod
    def duplicate_instance(
        db: Session,
        source_instance_id: int,
        new_instance_name: str,
        input_params: Optional[Dict[str, Any]] = None,
        created_by: Optional[str] = None
    ) -> Tuple[bool, str, Optional[WorkflowInstance]]:
        """
        复制工作流实例（基于已有实例创建新实例）

        Args:
            db: 数据库会话
            source_instance_id: 源实例ID
            new_instance_name: 新实例名称
            input_params: 输入参数（可覆盖源实例参数）
            created_by: 创建人

        Returns:
            (是否成功, 错误信息, 新工作流实例)
        """
        try:
            # 1. 获取源实例
            source_instance = db.query(WorkflowInstance).filter(
                WorkflowInstance.id == source_instance_id,
                WorkflowInstance.deleted_at.is_(None)
            ).first()

            if not source_instance:
                return False, "源实例不存在", None

            # 2. 准备参数
            # 如果没有提供新参数，使用源实例的参数
            if input_params is None and source_instance.input_params:
                try:
                    input_params = json.loads(source_instance.input_params)
                except:
                    input_params = {}

            # 3. 创建新实例（复制源实例的快照）
            # 新实例默认为"未运行"状态（与从模板创建保持一致）
            new_instance = WorkflowInstance(
                template_id=source_instance.template_id,
                template_version=source_instance.template_version,
                template_name=source_instance.template_name,
                workflow_definition_snapshot=source_instance.workflow_definition_snapshot,  # 复制快照
                instance_name=new_instance_name,
                status=WorkflowEngine.STATUS_NOT_STARTED,  # 未运行状态
                trigger_type="manual",  # 默认手动触发
                input_params=json.dumps(input_params or {}, ensure_ascii=False),
                cron_expression=source_instance.cron_expression,  # 复制定时配置
                cron_enabled=False,  # 默认不启用定时（避免重复调度）
                created_by=created_by or source_instance.created_by
            )

            db.add(new_instance)
            db.commit()
            db.refresh(new_instance)

            return True, "", new_instance

        except Exception as e:
            db.rollback()
            return False, f"复制实例失败: {str(e)}", None

    @staticmethod
    def save_instance_as_template(
        db: Session,
        instance_id: int,
        template_name: str,
        description: Optional[str] = None,
        created_by: Optional[str] = None
    ) -> Tuple[bool, str, Optional[WorkflowTemplate]]:
        """
        将实例另存为模板

        Args:
            db: 数据库会话
            instance_id: 实例ID
            template_name: 新模板名称
            description: 模板描述
            created_by: 创建人

        Returns:
            (是否成功, 错误信息, 新模板对象)
        """
        try:
            # 1. 获取实例
            instance = db.query(WorkflowInstance).filter(
                WorkflowInstance.id == instance_id,
                WorkflowInstance.deleted_at.is_(None)
            ).first()

            if not instance:
                return False, "实例不存在", None

            # 2. 检查是否有工作流定义快照
            if not instance.workflow_definition_snapshot:
                return False, "实例缺少工作流定义快照，无法创建模板", None

            # 3. 检查模板名称是否重复
            existing = db.query(WorkflowTemplate).filter(
                WorkflowTemplate.name == template_name,
                WorkflowTemplate.deleted_at.is_(None)
            ).first()

            if existing:
                return False, f"模板名称 '{template_name}' 已存在", None

            # 4. 创建新模板
            new_template = WorkflowTemplate(
                name=template_name,
                description=description or f"从实例 '{instance.instance_name}' 创建",
                workflow_definition=instance.workflow_definition_snapshot,  # 使用实例的快照
                version=1,
                parent_version_id=None,
                change_log=f"从工作流实例（ID: {instance_id}）创建",
                status="草稿",
                created_by=created_by or instance.created_by
            )

            db.add(new_template)
            db.commit()
            db.refresh(new_template)

            return True, "", new_template

        except Exception as e:
            db.rollback()
            return False, f"实例另存为模板失败: {str(e)}", None

    @staticmethod
    def update_instance_schedule(
        db: Session,
        instance_id: int,
        cron_expression: Optional[str] = None,
        cron_enabled: bool = False
    ) -> Tuple[bool, str]:
        """
        更新实例的定时调度配置

        Args:
            db: 数据库会话
            instance_id: 实例ID
            cron_expression: Cron 表达式
            cron_enabled: 是否启用定时调度

        Returns:
            (是否成功, 错误信息)
        """
        try:
            instance = db.query(WorkflowInstance).filter(
                WorkflowInstance.id == instance_id,
                WorkflowInstance.deleted_at.is_(None)
            ).first()

            if not instance:
                return False, "实例不存在"

            # 更新定时调度配置
            instance.cron_expression = cron_expression
            instance.cron_enabled = cron_enabled

            db.commit()

            return True, ""

        except Exception as e:
            db.rollback()
            return False, f"更新定时调度配置失败: {str(e)}"

    @staticmethod
    def check_circular_dependency(
        db: Session,
        instance_id: int,
        dependency_ids: list[int]
    ) -> Tuple[bool, Optional[list[int]]]:
        """
        检测循环依赖

        使用深度优先搜索（DFS）检测是否存在循环依赖

        Args:
            db: 数据库会话
            instance_id: 当前实例ID
            dependency_ids: 依赖的实例ID列表

        Returns:
            (是否存在循环, 循环路径)
        """
        # 构建依赖图
        dependency_graph = {}

        def load_dependencies(inst_id: int):
            """递归加载依赖关系"""
            if inst_id in dependency_graph:
                return

            instance = db.query(WorkflowInstance).filter(
                WorkflowInstance.id == inst_id,
                WorkflowInstance.deleted_at.is_(None)
            ).first()

            if not instance:
                dependency_graph[inst_id] = []
                return

            deps = []
            if instance.schedule_type == 'dependent' and instance.schedule_config:
                try:
                    config = json.loads(instance.schedule_config)
                    deps = config.get('dependency_instance_ids', [])
                except:
                    pass

            dependency_graph[inst_id] = deps

            # 递归加载每个依赖
            for dep_id in deps:
                load_dependencies(dep_id)

        # 加载当前实例的依赖
        dependency_graph[instance_id] = dependency_ids
        for dep_id in dependency_ids:
            load_dependencies(dep_id)

        # DFS 检测循环
        visited = set()
        rec_stack = set()
        cycle_path = []

        def dfs(node: int, path: list[int]) -> bool:
            """深度优先搜索检测循环"""
            visited.add(node)
            rec_stack.add(node)
            path.append(node)

            for neighbor in dependency_graph.get(node, []):
                if neighbor not in visited:
                    if dfs(neighbor, path):
                        return True
                elif neighbor in rec_stack:
                    # 找到循环
                    cycle_start_index = path.index(neighbor)
                    cycle_path.extend(path[cycle_start_index:])
                    cycle_path.append(neighbor)  # 闭合循环
                    return True

            path.pop()
            rec_stack.remove(node)
            return False

        if dfs(instance_id, []):
            return True, cycle_path

        return False, None

    @staticmethod
    def validate_schedule_config(
        db: Session,
        schedule_type: str,
        schedule_config: Optional[Dict[str, Any]],
        instance_id: Optional[int] = None
    ) -> Tuple[bool, str]:
        """
        验证调度配置的有效性

        Args:
            db: 数据库会话
            schedule_type: 调度类型
            schedule_config: 调度配置
            instance_id: 实例ID（用于循环检测）

        Returns:
            (是否有效, 错误信息)
        """
        if schedule_type in ('manual', 'create_only'):
            return True, ""

        if not schedule_config:
            return False, "调度配置为空"

        if schedule_type == 'scheduled':
            # 验证定时时间
            scheduled_time_str = schedule_config.get('scheduled_time')
            if not scheduled_time_str:
                return False, "未配置定时时间"

            try:
                from datetime import datetime
                scheduled_time = datetime.fromisoformat(scheduled_time_str)
                now = datetime.now()

                if scheduled_time <= now:
                    return False, "定时时间必须晚于当前时间"

                return True, ""
            except Exception as e:
                return False, f"定时时间格式无效: {str(e)}"

        if schedule_type == 'dependent':
            # 验证依赖实例
            dependency_ids = schedule_config.get('dependency_instance_ids', [])
            if not dependency_ids:
                return False, "未配置依赖实例"

            if not isinstance(dependency_ids, list):
                return False, "依赖实例ID必须是列表"

            # 检查依赖实例是否存在
            instances = db.query(WorkflowInstance).filter(
                WorkflowInstance.id.in_(dependency_ids),
                WorkflowInstance.deleted_at.is_(None)
            ).all()

            found_ids = {inst.id for inst in instances}
            missing_ids = set(dependency_ids) - found_ids
            if missing_ids:
                return False, f"依赖实例不存在: {list(missing_ids)}"

            # 检查循环依赖
            if instance_id:
                has_cycle, cycle_path = WorkflowInstanceService.check_circular_dependency(
                    db, instance_id, dependency_ids
                )
                if has_cycle:
                    return False, f"检测到循环依赖: {' -> '.join(map(str, cycle_path))}"

            return True, ""

        if schedule_type == 'cron':
            # 验证 CRON 表达式
            cron_expression = schedule_config.get('cron_expression')
            if not cron_expression:
                return False, "未配置 CRON 表达式"

            try:
                from apscheduler.triggers.cron import CronTrigger
                CronTrigger.from_crontab(cron_expression)
                return True, ""
            except Exception as e:
                return False, f"CRON 表达式无效: {str(e)}"

        return False, f"未知的调度类型: {schedule_type}"
